﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using TeamOPSchoolCup.Domain.DAL;
using TeamOPSchoolCup.Domain.POCO;
using TeamOPSchoolCup.Domain.POCO.Members;
using TeamOPSchoolCup.Domain.POCO.Ranking;
using TeamOPSchoolCup.Domain.POCO.Meetings;

namespace TeamOPSchoolCup.Domain.Services
{
  public class ResultService
  {

    public static bool AddResult(Result result)
    {
      bool r;
      using (EFDbContext db = new EFDbContext())
      {
        r = AddResult(db, result);
      }
      return r;
    }

    public static bool AddResult(EFDbContext db, Result result)
    {
      db.Results.Add(result);
      bool b=(db.SaveChanges() > 0);
      return b;
    }

    public static List<Result> GetResults(TeamMembership teamMembership=null, Team team=null, Student student=null, Event pEvent=null, int? competitionYear=null, RankingService.Officiality officiality = RankingService.Officiality.ALL, Meeting meeting=null)
    {
      List<Result> r;
      using (EFDbContext db = new EFDbContext())
      {
        r = GetResults(db, teamMembership, team, student, pEvent, competitionYear, officiality, meeting);
      }
      return r;
    }

    public static List<Result> GetResults(EFDbContext db, TeamMembership teamMembership=null, Team team=null, Student student=null, Event pEvent=null, int? competitionYear=null, RankingService.Officiality officiality=RankingService.Officiality.ALL, Meeting meeting=null)
    {
      List<Result> results = db.Results.Include("Event").Include("TeamMembership.Team").Include("TeamMembership.Student.Member").ToList();
      if (teamMembership != null) { results = results.Where(x => x.TeamMembership.Equals(teamMembership)).ToList(); }
      if (team != null) { results = results.Where(x => x.TeamId == team.TeamId).ToList(); }
      if (student != null) { results = results.Where(x => x.StudentId == student.StudentId).ToList(); }
      if (pEvent != null) { results = results.Where(x => x.EventId.Equals(pEvent.EventId)).ToList(); }
      if (competitionYear != null) { results = results.Where(x => x.Meeting.Date.Year == competitionYear.Value).ToList(); }
      if (officiality != RankingService.Officiality.ALL) {
        bool officialitybool = (officiality == RankingService.Officiality.OFFICIAL ? true : false);
        results = results.Where(x => x.Meeting.IsOfficial == officialitybool && x.Event.IsOfficial == officialitybool).ToList(); 
      }
      if (meeting != null) { results = results.Where(x => x.MeetingId == meeting.MeetingId).ToList(); }
      return results;
    }

    public static Result GetResult(int resultId)
    {
      Result r;
      using (EFDbContext db = new EFDbContext())
      {
        r = GetResult(db, resultId);
      }

      return r;
    }

    public static Result GetResult(EFDbContext db, int resultId)
    {
      return db.Results.Include("Event.Points").Single(x => x.ResultId==resultId);
    }

    public static bool UpdateResult(Result result)
    {
      bool r;
      using(EFDbContext db = new EFDbContext()){
        r = UpdateResult(db, result);
      }

      return r;
    }

    public static bool UpdateResult(EFDbContext db, Result result)
    {
      db.Entry(result).State = EntityState.Modified;

      return (db.SaveChanges() > 0);
    }

    //THE NEW CODE: 

    public static bool AddResults(EFDbContext db, List<Result> results, Meeting meeting)
    {
      bool b = false;
      results.ForEach(x => db.Results.Add(x));
      b = (db.SaveChanges() > 0);
      results.ForEach(x => RankingService.CalculateBestStudentResult(db, x));
      if (meeting.IsOfficial)
      {
        List<Team> teams = new List<Team>();
        foreach (Result r in results)
        {
          if (!teams.Contains(r.TeamMembership.Team))
          {
            teams.Add(r.TeamMembership.Team);
          }
        }

        foreach (Team t in teams)
        {
          RankingService.AddTeamResult(db, meeting, t);
        }
      }
      return b; //TODO This is not ideal
      //Loop over results and add them one by one
      //Save changes
      //CalculateBestStudentResult(student, event, year, officiality)
      //  Gets the event with the best resultscore within these parameters
      //If official (which would mean that all the results are added in one go)
      //  addTeamResult(meeting, team): get the best result per event, calculate its points, and add those together
      //    setBestTeamResult(team): get the teamResult with the highest points
    }

    public static List<Result> GetResults(EFDbContext db, Student student, Event pEvent, int year, TeamOPSchoolCup.Domain.Services.RankingService.Officiality officiality)
    {
      return db.Results.Where(x => x.StudentId == student.StudentId && x.EventId == pEvent.EventId && x.Meeting.Date.Year == year && x.Meeting.IsOfficial == (officiality == RankingService.Officiality.OFFICIAL) && x.Event.IsOfficial == (officiality == RankingService.Officiality.OFFICIAL)).ToList();
    }

    public static List<Result> GetResults(EFDbContext db, Meeting meeting, Team team)
    {
      return db.Results.Where(x => x.MeetingId == meeting.MeetingId && x.TeamMembership.TeamId == team.TeamId).ToList();
    }

    public static Result GetResultWithBestScoreWithinEvent(EFDbContext db, List<Result> results)
    {
      if (results.Count == 0) return null;
      Result maxResult = null;
      if (results.First().Event.Directionality == Event.EDirectionality.ASC)
      {
        maxResult = results.OrderByDescending(x => x.ResultScore).First();
      }
      else
      {
        maxResult = results.OrderBy(x => x.ResultScore).First();
      }
      return maxResult;
    }
  }
}
